#ifndef AUTODRIVE_POSTPROCESS_ID_GENERATOR_H_
#define AUTODRIVE_POSTPROCESS_ID_GENERATOR_H_

#include <cstdint>
#include <deque>
#include <array>
#include <thread>
#include <mutex>
#include <memory>
#include <stdexcept>

class PostProcessIdGenerator final {
 public:
  ~PostProcessIdGenerator() noexcept = default;
  PostProcessIdGenerator(PostProcessIdGenerator const&) = delete;
  PostProcessIdGenerator& operator=(PostProcessIdGenerator const&) = delete;
  PostProcessIdGenerator(PostProcessIdGenerator&&) = delete;
  PostProcessIdGenerator& operator=(PostProcessIdGenerator&&) = delete;

  /// @brief get single instance
  /// @return instance
  static PostProcessIdGenerator& GetInstance() noexcept;

  /// @brief Initialize
  void Init() noexcept;

  /// @brief Get id
  ///
  /// @throw OutOfResourceException  when no id available
  ///
  /// @return smallest available id
  std::uint16_t GetId() noexcept(false);

  /// @brief Get whether id is used
  ///
  /// @return is_id_used_[id]
  bool IsIdUsed(std::uint16_t id) const noexcept;

  /// @brief Release id
  ///
  /// @param id  id
  void ReleaseId(std::uint16_t id) noexcept(false);

 private:
  PostProcessIdGenerator() noexcept;
  /// @brief Max id
  static constexpr std::uint16_t kMaxId{2048U};
  /// @brief Task queue
  std::shared_ptr<std::deque<std::uint16_t>> id_queue_;
  /// @brief Whether one id is used
  std::shared_ptr<std::array<bool, kMaxId>> is_id_used_;
  /// @brief Mutex
  std::mutex mutex_;
  /// @brief init flag
  bool is_init_;
};

#endif  // AUTODRIVE_POSTPROCESS_ID_GENERATOR_H_

/* vim: set ts=2 sw=2 sts=2 tw=100 et: */
